#pragma once

#include <tuple>
#include <type_traits>

#include "OMIT_MeshAttrMacros.h"
#include "OMIT_MeshAttributes.h"

namespace OMIT_NAMESPACE
{
    namespace detail
    {
        template <typename T>
        struct _is_tuple : std::false_type {};

        template <typename... Args>
        struct _is_tuple<std::tuple<Args...>> : std::true_type {};

        // 检查 tuple 模板参数列表是否包含给定类型
        template <typename T, typename... Args>
        struct _is_in_tuple : std::false_type {};

        template <typename T, typename... Args>
        struct _is_in_tuple<T, std::tuple<T, Args...>> : std::true_type {};

        template <typename T, typename U, typename... Args>
        struct _is_in_tuple<T, std::tuple<U, Args...>> : _is_in_tuple<T, std::tuple<Args...>> {};

        // 检查类型是否在类型列表中
        template <typename T, typename... Args>
        struct _is_duplicate : std::disjunction<std::is_same<T, Args>...>{};

        // 检查参数类型都是属性参数类型
        template <typename T, typename... Args>
        struct _is_MeshAttr
        {
            static constexpr bool value = (std::is_base_of<_MeshAttr_Base<T>, T>::value && ... && std::is_base_of<_MeshAttr_Base<Args>, Args>::value);
        };

        // 定义一个模板类，用于检查参数列表中是否存在重复类型的参数
        template <typename... Args>
        struct _has_duplicate;

        template <typename Head, typename... Tail>
        struct _has_duplicate<Head, Tail...> {
            static constexpr bool value = _is_duplicate<Head, Tail...>::value || _has_duplicate<Tail...>::value;
        };

        template <typename T>
        struct _has_duplicate<T> {
            static constexpr bool value = false;
        };

        template <typename... TAttrs>
        struct _MeshAttrs_Traits : public TAttrs...
        {
            _MeshAttrs_Traits()
            {
                static_assert(!_has_duplicate<TAttrs...>::value, "Duplicate types inherited! Please remove the duplicate type of attributes in template arguments.");
                static_assert(_is_MeshAttr<TAttrs...>::value, "Invalid Attributes! Make sure the types of all attributes are derived from _OMIT::_MeshAttr_Base.");
            }

            static OMIT_MESHATTR_OUTPUT_NUMOPS ExportAllAttrOPs()
            {
                return OMIT_MESHATTR_OUTPUT_OPTION_ByType(TAttrs...);
            }

            using value_type = std::tuple<TAttrs...>;
        };
    }
}
